{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "345065a4",
   "metadata": {},
   "source": [
    "# Expert Knowledge Integration with Causal Discovery"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e1d422b1",
   "metadata": {},
   "source": [
    "Causal Discovery (aka. Structure learning) seeks to uncover the causal relationships among random variables from observational datasets. Methods like the PC algorithm and Hill-climb Search can be used for causal discovery, however, they often struggle to recover the correct causal relationships due to issues such as data not satisfying the assumptions of the method, limited data can lead to error, high compute time when there are many variables or the model is dense.\n",
    "\n",
    "Incorporating expert knowledge can greatly improve the accuracy of these methods, as well as reduce the computational cost as it constrains the search space for these algorithms. pgmpy currently has the following options to specify expert knowledge:\n",
    "- **Temporal Order / Tier information**: Specify the tiers/temporal order for sets of variables.\n",
    "- **Search Space**: Specify the set of edges that the algorithms should search through.\n",
    "- **Forbidden Edges**: Edges that should not be present in the final model.\n",
    "- **Required Edges**: Edges that must be present in the final model.\n",
    "\n",
    "This tutorial walks through examples of specifying expert knowledge with the causal discovery algorithms implemented in pgmpy. Expert knowledge is supported in pgmpy with the following algorithms:\n",
    "\n",
    "- **PC**\n",
    "- **Hill Climb Search**\n",
    "- **GES**\n",
    "- **ExpertInLoop**\n",
    "\n",
    "The models used in this notebook are described in detail at [the bnlearn repository](https://www.bnlearn.com/bnrepository/).\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d0d24cb4",
   "metadata": {},
   "source": [
    "## Temporal Order with  PC Algorithm"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "33f78cd0",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Imports and configuration\n",
    "import logging\n",
    "import itertools\n",
    "\n",
    "from IPython.display import display\n",
    "from pgmpy.utils import get_example_model\n",
    "from pgmpy.global_vars import logger, config\n",
    "\n",
    "logger.setLevel(logging.ERROR)\n",
    "config.set_backend(\"numpy\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "4f708849",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "f12b3917ef2e45f9b0f0de13fbd37c2d",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "  0%|          | 0/5 [00:00<?, ?it/s]"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/svg+xml": [
       "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n",
       "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"\n",
       " \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n",
       "<!-- Generated by graphviz version 2.43.0 (0)\n",
       " -->\n",
       "<!-- Title: unknown Pages: 1 -->\n",
       "<svg width=\"193pt\" height=\"188pt\"\n",
       " viewBox=\"0.00 0.00 193.15 188.00\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n",
       "<g id=\"graph0\" class=\"graph\" transform=\"scale(1 1) rotate(0) translate(4 184)\">\n",
       "<title>unknown</title>\n",
       "<polygon fill=\"white\" stroke=\"transparent\" points=\"-4,4 -4,-184 189.15,-184 189.15,4 -4,4\"/>\n",
       "<!-- Pollution -->\n",
       "<g id=\"node1\" class=\"node\">\n",
       "<title>Pollution</title>\n",
       "<ellipse fill=\"none\" stroke=\"black\" cx=\"43\" cy=\"-162\" rx=\"43\" ry=\"18\"/>\n",
       "<text text-anchor=\"middle\" x=\"43\" y=\"-158.3\" font-family=\"Times,serif\" font-size=\"14.00\">Pollution</text>\n",
       "</g>\n",
       "<!-- Cancer -->\n",
       "<g id=\"node2\" class=\"node\">\n",
       "<title>Cancer</title>\n",
       "<ellipse fill=\"none\" stroke=\"black\" cx=\"92\" cy=\"-90\" rx=\"36\" ry=\"18\"/>\n",
       "<text text-anchor=\"middle\" x=\"92\" y=\"-86.3\" font-family=\"Times,serif\" font-size=\"14.00\">Cancer</text>\n",
       "</g>\n",
       "<!-- Pollution&#45;&gt;Cancer -->\n",
       "<g id=\"edge1\" class=\"edge\">\n",
       "<title>Pollution&#45;&gt;Cancer</title>\n",
       "<path fill=\"none\" stroke=\"black\" d=\"M54.61,-144.41C60.59,-135.87 68,-125.28 74.65,-115.79\"/>\n",
       "<polygon fill=\"black\" stroke=\"black\" points=\"77.61,-117.67 80.47,-107.47 71.87,-113.66 77.61,-117.67\"/>\n",
       "</g>\n",
       "<!-- Xray -->\n",
       "<g id=\"node3\" class=\"node\">\n",
       "<title>Xray</title>\n",
       "<ellipse fill=\"none\" stroke=\"black\" cx=\"46\" cy=\"-18\" rx=\"28.7\" ry=\"18\"/>\n",
       "<text text-anchor=\"middle\" x=\"46\" y=\"-14.3\" font-family=\"Times,serif\" font-size=\"14.00\">Xray</text>\n",
       "</g>\n",
       "<!-- Cancer&#45;&gt;Xray -->\n",
       "<g id=\"edge2\" class=\"edge\">\n",
       "<title>Cancer&#45;&gt;Xray</title>\n",
       "<path fill=\"none\" stroke=\"black\" d=\"M81.33,-72.77C75.64,-64.11 68.52,-53.27 62.17,-43.6\"/>\n",
       "<polygon fill=\"black\" stroke=\"black\" points=\"65.03,-41.58 56.61,-35.15 59.18,-45.43 65.03,-41.58\"/>\n",
       "</g>\n",
       "<!-- Dyspnoea -->\n",
       "<g id=\"node4\" class=\"node\">\n",
       "<title>Dyspnoea</title>\n",
       "<ellipse fill=\"none\" stroke=\"black\" cx=\"139\" cy=\"-18\" rx=\"46.29\" ry=\"18\"/>\n",
       "<text text-anchor=\"middle\" x=\"139\" y=\"-14.3\" font-family=\"Times,serif\" font-size=\"14.00\">Dyspnoea</text>\n",
       "</g>\n",
       "<!-- Cancer&#45;&gt;Dyspnoea -->\n",
       "<g id=\"edge3\" class=\"edge\">\n",
       "<title>Cancer&#45;&gt;Dyspnoea</title>\n",
       "<path fill=\"none\" stroke=\"black\" d=\"M102.9,-72.77C108.63,-64.23 115.78,-53.58 122.2,-44.02\"/>\n",
       "<polygon fill=\"black\" stroke=\"black\" points=\"125.17,-45.89 127.83,-35.63 119.35,-41.98 125.17,-45.89\"/>\n",
       "</g>\n",
       "<!-- Smoker -->\n",
       "<g id=\"node5\" class=\"node\">\n",
       "<title>Smoker</title>\n",
       "<ellipse fill=\"none\" stroke=\"black\" cx=\"142\" cy=\"-162\" rx=\"38.5\" ry=\"18\"/>\n",
       "<text text-anchor=\"middle\" x=\"142\" y=\"-158.3\" font-family=\"Times,serif\" font-size=\"14.00\">Smoker</text>\n",
       "</g>\n",
       "<!-- Smoker&#45;&gt;Cancer -->\n",
       "<g id=\"edge4\" class=\"edge\">\n",
       "<title>Smoker&#45;&gt;Cancer</title>\n",
       "<path fill=\"none\" stroke=\"black\" d=\"M130.4,-144.76C124.15,-136.02 116.32,-125.05 109.36,-115.31\"/>\n",
       "<polygon fill=\"black\" stroke=\"black\" points=\"112.2,-113.25 103.53,-107.15 106.5,-117.32 112.2,-113.25\"/>\n",
       "</g>\n",
       "</g>\n",
       "</svg>\n"
      ],
      "text/plain": [
       "<AGraph b'unknown' <Swig Object of type 'Agraph_t *' at 0x7e5a9eb90e40>>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# Load an example model and simulate data from it.\n",
    "cancer = get_example_model(\"cancer\")\n",
    "cancer_samples = cancer.simulate(n_samples=5000, seed=42)\n",
    "\n",
    "# Plot the `cancer` model\n",
    "diag = cancer.to_graphviz()\n",
    "diag.layout(prog=\"dot\")\n",
    "display(diag)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "4b1a52da",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "22ce028ac25e4fb28411fa5bc2ac1997",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "  0%|          | 0/5 [00:00<?, ?it/s]"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/svg+xml": [
       "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n",
       "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"\n",
       " \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n",
       "<!-- Generated by graphviz version 2.43.0 (0)\n",
       " -->\n",
       "<!-- Pages: 1 -->\n",
       "<svg width=\"374pt\" height=\"116pt\"\n",
       " viewBox=\"0.00 0.00 374.15 116.00\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n",
       "<g id=\"graph0\" class=\"graph\" transform=\"scale(1 1) rotate(0) translate(4 112)\">\n",
       "<polygon fill=\"white\" stroke=\"transparent\" points=\"-4,4 -4,-112 370.15,-112 370.15,4 -4,4\"/>\n",
       "<!-- Dyspnoea -->\n",
       "<g id=\"node1\" class=\"node\">\n",
       "<title>Dyspnoea</title>\n",
       "<ellipse fill=\"none\" stroke=\"black\" cx=\"46.15\" cy=\"-90\" rx=\"46.29\" ry=\"18\"/>\n",
       "<text text-anchor=\"middle\" x=\"46.15\" y=\"-86.3\" font-family=\"Times,serif\" font-size=\"14.00\">Dyspnoea</text>\n",
       "</g>\n",
       "<!-- Cancer -->\n",
       "<g id=\"node2\" class=\"node\">\n",
       "<title>Cancer</title>\n",
       "<ellipse fill=\"none\" stroke=\"black\" cx=\"139.15\" cy=\"-18\" rx=\"36\" ry=\"18\"/>\n",
       "<text text-anchor=\"middle\" x=\"139.15\" y=\"-14.3\" font-family=\"Times,serif\" font-size=\"14.00\">Cancer</text>\n",
       "</g>\n",
       "<!-- Dyspnoea&#45;&gt;Cancer -->\n",
       "<g id=\"edge1\" class=\"edge\">\n",
       "<title>Dyspnoea&#45;&gt;Cancer</title>\n",
       "<path fill=\"none\" stroke=\"black\" d=\"M66.33,-73.81C79.63,-63.79 97.23,-50.55 111.79,-39.59\"/>\n",
       "<polygon fill=\"black\" stroke=\"black\" points=\"114.07,-42.25 119.96,-33.44 109.86,-36.66 114.07,-42.25\"/>\n",
       "</g>\n",
       "<!-- Xray -->\n",
       "<g id=\"node3\" class=\"node\">\n",
       "<title>Xray</title>\n",
       "<ellipse fill=\"none\" stroke=\"black\" cx=\"139.15\" cy=\"-90\" rx=\"28.7\" ry=\"18\"/>\n",
       "<text text-anchor=\"middle\" x=\"139.15\" y=\"-86.3\" font-family=\"Times,serif\" font-size=\"14.00\">Xray</text>\n",
       "</g>\n",
       "<!-- Xray&#45;&gt;Cancer -->\n",
       "<g id=\"edge2\" class=\"edge\">\n",
       "<title>Xray&#45;&gt;Cancer</title>\n",
       "<path fill=\"none\" stroke=\"black\" d=\"M139.15,-71.7C139.15,-63.98 139.15,-54.71 139.15,-46.11\"/>\n",
       "<polygon fill=\"black\" stroke=\"black\" points=\"142.65,-46.1 139.15,-36.1 135.65,-46.1 142.65,-46.1\"/>\n",
       "</g>\n",
       "<!-- Smoker -->\n",
       "<g id=\"node4\" class=\"node\">\n",
       "<title>Smoker</title>\n",
       "<ellipse fill=\"none\" stroke=\"black\" cx=\"224.15\" cy=\"-90\" rx=\"38.5\" ry=\"18\"/>\n",
       "<text text-anchor=\"middle\" x=\"224.15\" y=\"-86.3\" font-family=\"Times,serif\" font-size=\"14.00\">Smoker</text>\n",
       "</g>\n",
       "<!-- Smoker&#45;&gt;Cancer -->\n",
       "<g id=\"edge3\" class=\"edge\">\n",
       "<title>Smoker&#45;&gt;Cancer</title>\n",
       "<path fill=\"none\" stroke=\"black\" d=\"M205.7,-73.81C193.73,-63.95 177.97,-50.97 164.79,-40.12\"/>\n",
       "<polygon fill=\"black\" stroke=\"black\" points=\"166.92,-37.33 156.97,-33.68 162.47,-42.74 166.92,-37.33\"/>\n",
       "</g>\n",
       "<!-- Pollution -->\n",
       "<g id=\"node5\" class=\"node\">\n",
       "<title>Pollution</title>\n",
       "<ellipse fill=\"none\" stroke=\"black\" cx=\"323.15\" cy=\"-90\" rx=\"43\" ry=\"18\"/>\n",
       "<text text-anchor=\"middle\" x=\"323.15\" y=\"-86.3\" font-family=\"Times,serif\" font-size=\"14.00\">Pollution</text>\n",
       "</g>\n",
       "</g>\n",
       "</svg>\n"
      ],
      "text/plain": [
       "<AGraph <Swig Object of type 'Agraph_t *' at 0x7e5a9db0bb10>>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# Run the standard PC algorithm and plot the results\n",
    "\n",
    "from pgmpy.estimators import PC, ExpertKnowledge\n",
    "\n",
    "learned_model = PC(cancer_samples).estimate()\n",
    "\n",
    "diag = learned_model.to_graphviz()\n",
    "diag.layout(prog=\"dot\")\n",
    "display(diag)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7340f704",
   "metadata": {},
   "source": [
    "As seen from the learned model, the PC algorithm was not able to correctly recover the original data-generating DAG. \n",
    "\n",
    "Now, we know that smoking (`Smoker`) and air pollution (`Pollution`) contribute to lung cancer (`Cancer`). Also, breathing difficulties (`Dyspnoea`) and a positive X-ray report (`Xray`) contribute to a cancer diagnosis (effect), so they cannot be the initial causes in this scenario. Based on this, we can craft a temporal order where the causes of cancer are at a higher temporal order, while the effects are lumped together at the end."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "66b91a8d",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "e26c8f630ac94230b2a3d30c64511087",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "  0%|          | 0/5 [00:00<?, ?it/s]"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/svg+xml": [
       "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n",
       "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"\n",
       " \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n",
       "<!-- Generated by graphviz version 2.43.0 (0)\n",
       " -->\n",
       "<!-- Pages: 1 -->\n",
       "<svg width=\"189pt\" height=\"188pt\"\n",
       " viewBox=\"0.00 0.00 188.65 188.00\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n",
       "<g id=\"graph0\" class=\"graph\" transform=\"scale(1 1) rotate(0) translate(4 184)\">\n",
       "<polygon fill=\"white\" stroke=\"transparent\" points=\"-4,4 -4,-184 184.65,-184 184.65,4 -4,4\"/>\n",
       "<!-- Pollution -->\n",
       "<g id=\"node1\" class=\"node\">\n",
       "<title>Pollution</title>\n",
       "<ellipse fill=\"none\" stroke=\"black\" cx=\"43.15\" cy=\"-162\" rx=\"43\" ry=\"18\"/>\n",
       "<text text-anchor=\"middle\" x=\"43.15\" y=\"-158.3\" font-family=\"Times,serif\" font-size=\"14.00\">Pollution</text>\n",
       "</g>\n",
       "<!-- Cancer -->\n",
       "<g id=\"node2\" class=\"node\">\n",
       "<title>Cancer</title>\n",
       "<ellipse fill=\"none\" stroke=\"black\" cx=\"92.15\" cy=\"-90\" rx=\"36\" ry=\"18\"/>\n",
       "<text text-anchor=\"middle\" x=\"92.15\" y=\"-86.3\" font-family=\"Times,serif\" font-size=\"14.00\">Cancer</text>\n",
       "</g>\n",
       "<!-- Pollution&#45;&gt;Cancer -->\n",
       "<g id=\"edge1\" class=\"edge\">\n",
       "<title>Pollution&#45;&gt;Cancer</title>\n",
       "<path fill=\"none\" stroke=\"black\" d=\"M54.76,-144.41C60.74,-135.87 68.15,-125.28 74.79,-115.79\"/>\n",
       "<polygon fill=\"black\" stroke=\"black\" points=\"77.75,-117.67 80.62,-107.47 72.02,-113.66 77.75,-117.67\"/>\n",
       "</g>\n",
       "<!-- Dyspnoea -->\n",
       "<g id=\"node3\" class=\"node\">\n",
       "<title>Dyspnoea</title>\n",
       "<ellipse fill=\"none\" stroke=\"black\" cx=\"46.15\" cy=\"-18\" rx=\"46.29\" ry=\"18\"/>\n",
       "<text text-anchor=\"middle\" x=\"46.15\" y=\"-14.3\" font-family=\"Times,serif\" font-size=\"14.00\">Dyspnoea</text>\n",
       "</g>\n",
       "<!-- Cancer&#45;&gt;Dyspnoea -->\n",
       "<g id=\"edge2\" class=\"edge\">\n",
       "<title>Cancer&#45;&gt;Dyspnoea</title>\n",
       "<path fill=\"none\" stroke=\"black\" d=\"M81.48,-72.77C75.87,-64.23 68.87,-53.58 62.59,-44.02\"/>\n",
       "<polygon fill=\"black\" stroke=\"black\" points=\"65.49,-42.07 57.08,-35.63 59.64,-45.91 65.49,-42.07\"/>\n",
       "</g>\n",
       "<!-- Xray -->\n",
       "<g id=\"node4\" class=\"node\">\n",
       "<title>Xray</title>\n",
       "<ellipse fill=\"none\" stroke=\"black\" cx=\"139.15\" cy=\"-18\" rx=\"28.7\" ry=\"18\"/>\n",
       "<text text-anchor=\"middle\" x=\"139.15\" y=\"-14.3\" font-family=\"Times,serif\" font-size=\"14.00\">Xray</text>\n",
       "</g>\n",
       "<!-- Cancer&#45;&gt;Xray -->\n",
       "<g id=\"edge3\" class=\"edge\">\n",
       "<title>Cancer&#45;&gt;Xray</title>\n",
       "<path fill=\"none\" stroke=\"black\" d=\"M103.05,-72.77C108.86,-64.11 116.13,-53.27 122.63,-43.6\"/>\n",
       "<polygon fill=\"black\" stroke=\"black\" points=\"125.64,-45.4 128.3,-35.15 119.82,-41.5 125.64,-45.4\"/>\n",
       "</g>\n",
       "<!-- Smoker -->\n",
       "<g id=\"node5\" class=\"node\">\n",
       "<title>Smoker</title>\n",
       "<ellipse fill=\"none\" stroke=\"black\" cx=\"142.15\" cy=\"-162\" rx=\"38.5\" ry=\"18\"/>\n",
       "<text text-anchor=\"middle\" x=\"142.15\" y=\"-158.3\" font-family=\"Times,serif\" font-size=\"14.00\">Smoker</text>\n",
       "</g>\n",
       "<!-- Smoker&#45;&gt;Cancer -->\n",
       "<g id=\"edge4\" class=\"edge\">\n",
       "<title>Smoker&#45;&gt;Cancer</title>\n",
       "<path fill=\"none\" stroke=\"black\" d=\"M130.55,-144.76C124.3,-136.02 116.47,-125.05 109.51,-115.31\"/>\n",
       "<polygon fill=\"black\" stroke=\"black\" points=\"112.34,-113.25 103.68,-107.15 106.65,-117.32 112.34,-113.25\"/>\n",
       "</g>\n",
       "</g>\n",
       "</svg>\n"
      ],
      "text/plain": [
       "<AGraph <Swig Object of type 'Agraph_t *' at 0x7e5aa521c420>>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# PC algorithm with the temporal knowledge.\n",
    "\n",
    "expert_knowledge = ExpertKnowledge(\n",
    "    temporal_order=[[\"Pollution\", \"Smoker\"], [\"Cancer\"], [\"Dyspnoea\", \"Xray\"]]\n",
    ")\n",
    "\n",
    "est_model = PC(cancer_samples).estimate(expert_knowledge=expert_knowledge)\n",
    "\n",
    "diag = est_model.to_graphviz()\n",
    "diag.layout(prog=\"dot\")\n",
    "display(diag)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d943d672",
   "metadata": {},
   "source": [
    "Note: Using any form of expert knowledge, especially with PC, is sensitive to the accuracy of the knowledge."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "705df5c8",
   "metadata": {},
   "source": [
    "## Expert knowledge based on search space "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "129dbf0c",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "22c18d7324bf42158d08524faac44a58",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "  0%|          | 0/8 [00:00<?, ?it/s]"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/svg+xml": [
       "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n",
       "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"\n",
       " \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n",
       "<!-- Generated by graphviz version 2.43.0 (0)\n",
       " -->\n",
       "<!-- Title: unknown Pages: 1 -->\n",
       "<svg width=\"193pt\" height=\"260pt\"\n",
       " viewBox=\"0.00 0.00 192.55 260.00\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n",
       "<g id=\"graph0\" class=\"graph\" transform=\"scale(1 1) rotate(0) translate(4 256)\">\n",
       "<title>unknown</title>\n",
       "<polygon fill=\"white\" stroke=\"transparent\" points=\"-4,4 -4,-256 188.55,-256 188.55,4 -4,4\"/>\n",
       "<!-- asia -->\n",
       "<g id=\"node1\" class=\"node\">\n",
       "<title>asia</title>\n",
       "<ellipse fill=\"none\" stroke=\"black\" cx=\"27\" cy=\"-234\" rx=\"27\" ry=\"18\"/>\n",
       "<text text-anchor=\"middle\" x=\"27\" y=\"-230.3\" font-family=\"Times,serif\" font-size=\"14.00\">asia</text>\n",
       "</g>\n",
       "<!-- tub -->\n",
       "<g id=\"node2\" class=\"node\">\n",
       "<title>tub</title>\n",
       "<ellipse fill=\"none\" stroke=\"black\" cx=\"27\" cy=\"-162\" rx=\"27\" ry=\"18\"/>\n",
       "<text text-anchor=\"middle\" x=\"27\" y=\"-158.3\" font-family=\"Times,serif\" font-size=\"14.00\">tub</text>\n",
       "</g>\n",
       "<!-- asia&#45;&gt;tub -->\n",
       "<g id=\"edge1\" class=\"edge\">\n",
       "<title>asia&#45;&gt;tub</title>\n",
       "<path fill=\"none\" stroke=\"black\" d=\"M27,-215.7C27,-207.98 27,-198.71 27,-190.11\"/>\n",
       "<polygon fill=\"black\" stroke=\"black\" points=\"30.5,-190.1 27,-180.1 23.5,-190.1 30.5,-190.1\"/>\n",
       "</g>\n",
       "<!-- either -->\n",
       "<g id=\"node3\" class=\"node\">\n",
       "<title>either</title>\n",
       "<ellipse fill=\"none\" stroke=\"black\" cx=\"75\" cy=\"-90\" rx=\"30.59\" ry=\"18\"/>\n",
       "<text text-anchor=\"middle\" x=\"75\" y=\"-86.3\" font-family=\"Times,serif\" font-size=\"14.00\">either</text>\n",
       "</g>\n",
       "<!-- tub&#45;&gt;either -->\n",
       "<g id=\"edge2\" class=\"edge\">\n",
       "<title>tub&#45;&gt;either</title>\n",
       "<path fill=\"none\" stroke=\"black\" d=\"M37.89,-145.12C43.82,-136.47 51.29,-125.58 57.97,-115.83\"/>\n",
       "<polygon fill=\"black\" stroke=\"black\" points=\"61.05,-117.54 63.82,-107.31 55.27,-113.58 61.05,-117.54\"/>\n",
       "</g>\n",
       "<!-- dysp -->\n",
       "<g id=\"node4\" class=\"node\">\n",
       "<title>dysp</title>\n",
       "<ellipse fill=\"none\" stroke=\"black\" cx=\"150\" cy=\"-18\" rx=\"27.5\" ry=\"18\"/>\n",
       "<text text-anchor=\"middle\" x=\"150\" y=\"-14.3\" font-family=\"Times,serif\" font-size=\"14.00\">dysp</text>\n",
       "</g>\n",
       "<!-- either&#45;&gt;dysp -->\n",
       "<g id=\"edge3\" class=\"edge\">\n",
       "<title>either&#45;&gt;dysp</title>\n",
       "<path fill=\"none\" stroke=\"black\" d=\"M90.54,-74.5C101.17,-64.58 115.43,-51.26 127.33,-40.16\"/>\n",
       "<polygon fill=\"black\" stroke=\"black\" points=\"129.82,-42.63 134.74,-33.25 125.04,-37.51 129.82,-42.63\"/>\n",
       "</g>\n",
       "<!-- xray -->\n",
       "<g id=\"node5\" class=\"node\">\n",
       "<title>xray</title>\n",
       "<ellipse fill=\"none\" stroke=\"black\" cx=\"75\" cy=\"-18\" rx=\"27\" ry=\"18\"/>\n",
       "<text text-anchor=\"middle\" x=\"75\" y=\"-14.3\" font-family=\"Times,serif\" font-size=\"14.00\">xray</text>\n",
       "</g>\n",
       "<!-- either&#45;&gt;xray -->\n",
       "<g id=\"edge4\" class=\"edge\">\n",
       "<title>either&#45;&gt;xray</title>\n",
       "<path fill=\"none\" stroke=\"black\" d=\"M75,-71.7C75,-63.98 75,-54.71 75,-46.11\"/>\n",
       "<polygon fill=\"black\" stroke=\"black\" points=\"78.5,-46.1 75,-36.1 71.5,-46.1 78.5,-46.1\"/>\n",
       "</g>\n",
       "<!-- smoke -->\n",
       "<g id=\"node6\" class=\"node\">\n",
       "<title>smoke</title>\n",
       "<ellipse fill=\"none\" stroke=\"black\" cx=\"130\" cy=\"-234\" rx=\"34.5\" ry=\"18\"/>\n",
       "<text text-anchor=\"middle\" x=\"130\" y=\"-230.3\" font-family=\"Times,serif\" font-size=\"14.00\">smoke</text>\n",
       "</g>\n",
       "<!-- lung -->\n",
       "<g id=\"node7\" class=\"node\">\n",
       "<title>lung</title>\n",
       "<ellipse fill=\"none\" stroke=\"black\" cx=\"99\" cy=\"-162\" rx=\"27\" ry=\"18\"/>\n",
       "<text text-anchor=\"middle\" x=\"99\" y=\"-158.3\" font-family=\"Times,serif\" font-size=\"14.00\">lung</text>\n",
       "</g>\n",
       "<!-- smoke&#45;&gt;lung -->\n",
       "<g id=\"edge5\" class=\"edge\">\n",
       "<title>smoke&#45;&gt;lung</title>\n",
       "<path fill=\"none\" stroke=\"black\" d=\"M122.65,-216.41C118.99,-208.13 114.47,-197.92 110.36,-188.66\"/>\n",
       "<polygon fill=\"black\" stroke=\"black\" points=\"113.54,-187.2 106.29,-179.47 107.14,-190.03 113.54,-187.2\"/>\n",
       "</g>\n",
       "<!-- bronc -->\n",
       "<g id=\"node8\" class=\"node\">\n",
       "<title>bronc</title>\n",
       "<ellipse fill=\"none\" stroke=\"black\" cx=\"154\" cy=\"-90\" rx=\"30.59\" ry=\"18\"/>\n",
       "<text text-anchor=\"middle\" x=\"154\" y=\"-86.3\" font-family=\"Times,serif\" font-size=\"14.00\">bronc</text>\n",
       "</g>\n",
       "<!-- smoke&#45;&gt;bronc -->\n",
       "<g id=\"edge6\" class=\"edge\">\n",
       "<title>smoke&#45;&gt;bronc</title>\n",
       "<path fill=\"none\" stroke=\"black\" d=\"M132.89,-215.87C136.99,-191.67 144.5,-147.21 149.37,-118.39\"/>\n",
       "<polygon fill=\"black\" stroke=\"black\" points=\"152.88,-118.63 151.09,-108.19 145.98,-117.47 152.88,-118.63\"/>\n",
       "</g>\n",
       "<!-- lung&#45;&gt;either -->\n",
       "<g id=\"edge7\" class=\"edge\">\n",
       "<title>lung&#45;&gt;either</title>\n",
       "<path fill=\"none\" stroke=\"black\" d=\"M93.19,-144.05C90.45,-136.06 87.11,-126.33 84.05,-117.4\"/>\n",
       "<polygon fill=\"black\" stroke=\"black\" points=\"87.31,-116.11 80.76,-107.79 80.69,-118.38 87.31,-116.11\"/>\n",
       "</g>\n",
       "<!-- bronc&#45;&gt;dysp -->\n",
       "<g id=\"edge8\" class=\"edge\">\n",
       "<title>bronc&#45;&gt;dysp</title>\n",
       "<path fill=\"none\" stroke=\"black\" d=\"M153.01,-71.7C152.57,-63.98 152.04,-54.71 151.55,-46.11\"/>\n",
       "<polygon fill=\"black\" stroke=\"black\" points=\"155.04,-45.89 150.98,-36.1 148.05,-46.29 155.04,-45.89\"/>\n",
       "</g>\n",
       "</g>\n",
       "</svg>\n"
      ],
      "text/plain": [
       "<AGraph b'unknown' <Swig Object of type 'Agraph_t *' at 0x7e5aa51c1770>>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# Load the Asia model and simulate data (https://www.bnlearn.com/bnrepository/discrete-small.html#asia)\n",
    "asia = get_example_model(\"asia\")\n",
    "asia_samples = asia.simulate(n_samples=10000, seed=42)\n",
    "\n",
    "diag = asia.to_graphviz()\n",
    "diag.layout(prog=\"dot\")\n",
    "display(diag)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f88e492f",
   "metadata": {},
   "source": [
    "The idea with the search space is that it is usually difficult to distinguish between direct and indirect effects. For example, in the above Asia model, we might know that `smoke` would have a causal effect on `dysp` but might not exactly know through which pathways. With the search space, we try to specify a hypergraph over our variables such that we specify a causal edge between any two variables that we think should have a causal relationship, but aren't sure about the causal path/edges.\n",
    "\n",
    "As an example, for the `asia` model, we can consider additional edges from all three diseases (`tub`, `lung`, and `bronc`) to both the symptoms (`xray` and `dysp`). "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "56a67b5a",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "5d011a252da542e2b86c84964a3635bd",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "  0%|          | 0/5 [00:00<?, ?it/s]"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "8"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from pgmpy.metrics import SHD\n",
    "\n",
    "search_space = [\n",
    "    (\"smoke\", \"cancer\"),\n",
    "    (\"smoke\", \"lung\"),\n",
    "    (\"smoke\", \"tub\"),\n",
    "    (\"tub\", \"asia\"),\n",
    "    (\"asia\", \"tub\"),\n",
    "    (\"tub\", \"either\"),\n",
    "    (\"lung\", \"either\"),\n",
    "    (\"bronc\", \"either\"),\n",
    "    (\"tub\", \"xray\"),\n",
    "    (\"tub\", \"dysp\"),\n",
    "    (\"lung\", \"x-ray\"),\n",
    "    (\"lung\", \"dysp\"),\n",
    "    (\"bronc\", \"xray\"),\n",
    "    (\"bronc\", \"dysp\"),\n",
    "    (\"either\", \"xray\"),\n",
    "    (\"either\", \"dysp\"),\n",
    "    (\"tub\", \"dysp\"),\n",
    "]\n",
    "\n",
    "expert_knowledge = ExpertKnowledge(search_space=search_space)\n",
    "\n",
    "est_model = PC(asia_samples).estimate(expert_knowledge=expert_knowledge, ci_test='pillai', enforce_expert_knowledge=True)\n",
    "SHD(asia, est_model)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "40b488fa",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/svg+xml": [
       "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n",
       "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"\n",
       " \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n",
       "<!-- Generated by graphviz version 2.43.0 (0)\n",
       " -->\n",
       "<!-- Pages: 1 -->\n",
       "<svg width=\"525pt\" height=\"116pt\"\n",
       " viewBox=\"0.00 0.00 524.55 116.00\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n",
       "<g id=\"graph0\" class=\"graph\" transform=\"scale(1 1) rotate(0) translate(4 112)\">\n",
       "<polygon fill=\"white\" stroke=\"transparent\" points=\"-4,4 -4,-112 520.55,-112 520.55,4 -4,4\"/>\n",
       "<!-- asia -->\n",
       "<g id=\"node1\" class=\"node\">\n",
       "<title>asia</title>\n",
       "<ellipse fill=\"none\" stroke=\"black\" cx=\"27\" cy=\"-90\" rx=\"27\" ry=\"18\"/>\n",
       "<text text-anchor=\"middle\" x=\"27\" y=\"-86.3\" font-family=\"Times,serif\" font-size=\"14.00\">asia</text>\n",
       "</g>\n",
       "<!-- tub -->\n",
       "<g id=\"node2\" class=\"node\">\n",
       "<title>tub</title>\n",
       "<ellipse fill=\"none\" stroke=\"black\" cx=\"27\" cy=\"-18\" rx=\"27\" ry=\"18\"/>\n",
       "<text text-anchor=\"middle\" x=\"27\" y=\"-14.3\" font-family=\"Times,serif\" font-size=\"14.00\">tub</text>\n",
       "</g>\n",
       "<!-- asia&#45;&gt;tub -->\n",
       "<g id=\"edge1\" class=\"edge\">\n",
       "<title>asia&#45;&gt;tub</title>\n",
       "<path fill=\"none\" stroke=\"black\" d=\"M21.16,-72.41C20.3,-64.51 20.05,-54.85 20.41,-45.94\"/>\n",
       "<polygon fill=\"black\" stroke=\"black\" points=\"23.9,-46.18 21.12,-35.96 16.92,-45.68 23.9,-46.18\"/>\n",
       "</g>\n",
       "<!-- tub&#45;&gt;asia -->\n",
       "<g id=\"edge2\" class=\"edge\">\n",
       "<title>tub&#45;&gt;asia</title>\n",
       "<path fill=\"none\" stroke=\"black\" d=\"M32.88,-35.96C33.71,-43.83 33.95,-53.37 33.58,-62.19\"/>\n",
       "<polygon fill=\"black\" stroke=\"black\" points=\"30.07,-62.18 32.84,-72.41 37.06,-62.69 30.07,-62.18\"/>\n",
       "</g>\n",
       "<!-- lung -->\n",
       "<g id=\"node3\" class=\"node\">\n",
       "<title>lung</title>\n",
       "<ellipse fill=\"none\" stroke=\"black\" cx=\"99\" cy=\"-90\" rx=\"27\" ry=\"18\"/>\n",
       "<text text-anchor=\"middle\" x=\"99\" y=\"-86.3\" font-family=\"Times,serif\" font-size=\"14.00\">lung</text>\n",
       "</g>\n",
       "<!-- bronc -->\n",
       "<g id=\"node4\" class=\"node\">\n",
       "<title>bronc</title>\n",
       "<ellipse fill=\"none\" stroke=\"black\" cx=\"175\" cy=\"-90\" rx=\"30.59\" ry=\"18\"/>\n",
       "<text text-anchor=\"middle\" x=\"175\" y=\"-86.3\" font-family=\"Times,serif\" font-size=\"14.00\">bronc</text>\n",
       "</g>\n",
       "<!-- dysp -->\n",
       "<g id=\"node5\" class=\"node\">\n",
       "<title>dysp</title>\n",
       "<ellipse fill=\"none\" stroke=\"black\" cx=\"251\" cy=\"-90\" rx=\"27.5\" ry=\"18\"/>\n",
       "<text text-anchor=\"middle\" x=\"251\" y=\"-86.3\" font-family=\"Times,serif\" font-size=\"14.00\">dysp</text>\n",
       "</g>\n",
       "<!-- smoke -->\n",
       "<g id=\"node6\" class=\"node\">\n",
       "<title>smoke</title>\n",
       "<ellipse fill=\"none\" stroke=\"black\" cx=\"331\" cy=\"-90\" rx=\"34.5\" ry=\"18\"/>\n",
       "<text text-anchor=\"middle\" x=\"331\" y=\"-86.3\" font-family=\"Times,serif\" font-size=\"14.00\">smoke</text>\n",
       "</g>\n",
       "<!-- xray -->\n",
       "<g id=\"node7\" class=\"node\">\n",
       "<title>xray</title>\n",
       "<ellipse fill=\"none\" stroke=\"black\" cx=\"410\" cy=\"-90\" rx=\"27\" ry=\"18\"/>\n",
       "<text text-anchor=\"middle\" x=\"410\" y=\"-86.3\" font-family=\"Times,serif\" font-size=\"14.00\">xray</text>\n",
       "</g>\n",
       "<!-- either -->\n",
       "<g id=\"node8\" class=\"node\">\n",
       "<title>either</title>\n",
       "<ellipse fill=\"none\" stroke=\"black\" cx=\"486\" cy=\"-90\" rx=\"30.59\" ry=\"18\"/>\n",
       "<text text-anchor=\"middle\" x=\"486\" y=\"-86.3\" font-family=\"Times,serif\" font-size=\"14.00\">either</text>\n",
       "</g>\n",
       "</g>\n",
       "</svg>\n"
      ],
      "text/plain": [
       "<AGraph <Swig Object of type 'Agraph_t *' at 0x7e5a9e058810>>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# Plot the estimated model\n",
    "\n",
    "diag = est_model.to_graphviz()\n",
    "diag.layout(prog=\"dot\")\n",
    "display(diag)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3cdc03f6",
   "metadata": {},
   "source": [
    "## Knowledge base of required and forbidden edges"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "b81d935b",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "c2e6b6fc46b547369d2ec99db880478b",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "  0%|          | 0/20 [00:00<?, ?it/s]"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/svg+xml": [
       "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n",
       "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"\n",
       " \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n",
       "<!-- Generated by graphviz version 2.43.0 (0)\n",
       " -->\n",
       "<!-- Title: unknown Pages: 1 -->\n",
       "<svg width=\"733pt\" height=\"332pt\"\n",
       " viewBox=\"0.00 0.00 733.05 332.00\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n",
       "<g id=\"graph0\" class=\"graph\" transform=\"scale(1 1) rotate(0) translate(4 328)\">\n",
       "<title>unknown</title>\n",
       "<polygon fill=\"white\" stroke=\"transparent\" points=\"-4,4 -4,-328 729.05,-328 729.05,4 -4,4\"/>\n",
       "<!-- BirthAsphyxia -->\n",
       "<g id=\"node1\" class=\"node\">\n",
       "<title>BirthAsphyxia</title>\n",
       "<ellipse fill=\"none\" stroke=\"black\" cx=\"305\" cy=\"-306\" rx=\"62.5\" ry=\"18\"/>\n",
       "<text text-anchor=\"middle\" x=\"305\" y=\"-302.3\" font-family=\"Times,serif\" font-size=\"14.00\">BirthAsphyxia</text>\n",
       "</g>\n",
       "<!-- Disease -->\n",
       "<g id=\"node2\" class=\"node\">\n",
       "<title>Disease</title>\n",
       "<ellipse fill=\"none\" stroke=\"black\" cx=\"305\" cy=\"-234\" rx=\"38.5\" ry=\"18\"/>\n",
       "<text text-anchor=\"middle\" x=\"305\" y=\"-230.3\" font-family=\"Times,serif\" font-size=\"14.00\">Disease</text>\n",
       "</g>\n",
       "<!-- BirthAsphyxia&#45;&gt;Disease -->\n",
       "<g id=\"edge1\" class=\"edge\">\n",
       "<title>BirthAsphyxia&#45;&gt;Disease</title>\n",
       "<path fill=\"none\" stroke=\"black\" d=\"M305,-287.7C305,-279.98 305,-270.71 305,-262.11\"/>\n",
       "<polygon fill=\"black\" stroke=\"black\" points=\"308.5,-262.1 305,-252.1 301.5,-262.1 308.5,-262.1\"/>\n",
       "</g>\n",
       "<!-- Age -->\n",
       "<g id=\"node3\" class=\"node\">\n",
       "<title>Age</title>\n",
       "<ellipse fill=\"none\" stroke=\"black\" cx=\"27\" cy=\"-90\" rx=\"27\" ry=\"18\"/>\n",
       "<text text-anchor=\"middle\" x=\"27\" y=\"-86.3\" font-family=\"Times,serif\" font-size=\"14.00\">Age</text>\n",
       "</g>\n",
       "<!-- Disease&#45;&gt;Age -->\n",
       "<g id=\"edge2\" class=\"edge\">\n",
       "<title>Disease&#45;&gt;Age</title>\n",
       "<path fill=\"none\" stroke=\"black\" d=\"M267.6,-230.02C204.52,-224.24 80.85,-209.4 50,-180 33.35,-164.13 28.16,-137.93 26.8,-118.05\"/>\n",
       "<polygon fill=\"black\" stroke=\"black\" points=\"30.3,-117.9 26.39,-108.05 23.3,-118.18 30.3,-117.9\"/>\n",
       "</g>\n",
       "<!-- LVH -->\n",
       "<g id=\"node4\" class=\"node\">\n",
       "<title>LVH</title>\n",
       "<ellipse fill=\"none\" stroke=\"black\" cx=\"663\" cy=\"-162\" rx=\"28.7\" ry=\"18\"/>\n",
       "<text text-anchor=\"middle\" x=\"663\" y=\"-158.3\" font-family=\"Times,serif\" font-size=\"14.00\">LVH</text>\n",
       "</g>\n",
       "<!-- Disease&#45;&gt;LVH -->\n",
       "<g id=\"edge3\" class=\"edge\">\n",
       "<title>Disease&#45;&gt;LVH</title>\n",
       "<path fill=\"none\" stroke=\"black\" d=\"M342.51,-229.79C402.83,-223.95 524.68,-209.41 624,-180 626.48,-179.27 629.01,-178.42 631.53,-177.49\"/>\n",
       "<polygon fill=\"black\" stroke=\"black\" points=\"633.09,-180.64 641.08,-173.68 630.49,-174.13 633.09,-180.64\"/>\n",
       "</g>\n",
       "<!-- DuctFlow -->\n",
       "<g id=\"node5\" class=\"node\">\n",
       "<title>DuctFlow</title>\n",
       "<ellipse fill=\"none\" stroke=\"black\" cx=\"177\" cy=\"-162\" rx=\"46.29\" ry=\"18\"/>\n",
       "<text text-anchor=\"middle\" x=\"177\" y=\"-158.3\" font-family=\"Times,serif\" font-size=\"14.00\">DuctFlow</text>\n",
       "</g>\n",
       "<!-- Disease&#45;&gt;DuctFlow -->\n",
       "<g id=\"edge4\" class=\"edge\">\n",
       "<title>Disease&#45;&gt;DuctFlow</title>\n",
       "<path fill=\"none\" stroke=\"black\" d=\"M280.92,-219.83C261.41,-209.16 233.64,-193.98 211.72,-181.99\"/>\n",
       "<polygon fill=\"black\" stroke=\"black\" points=\"213.17,-178.8 202.72,-177.07 209.82,-184.94 213.17,-178.8\"/>\n",
       "</g>\n",
       "<!-- CardiacMixing -->\n",
       "<g id=\"node6\" class=\"node\">\n",
       "<title>CardiacMixing</title>\n",
       "<ellipse fill=\"none\" stroke=\"black\" cx=\"305\" cy=\"-162\" rx=\"64.5\" ry=\"18\"/>\n",
       "<text text-anchor=\"middle\" x=\"305\" y=\"-158.3\" font-family=\"Times,serif\" font-size=\"14.00\">CardiacMixing</text>\n",
       "</g>\n",
       "<!-- Disease&#45;&gt;CardiacMixing -->\n",
       "<g id=\"edge5\" class=\"edge\">\n",
       "<title>Disease&#45;&gt;CardiacMixing</title>\n",
       "<path fill=\"none\" stroke=\"black\" d=\"M305,-215.7C305,-207.98 305,-198.71 305,-190.11\"/>\n",
       "<polygon fill=\"black\" stroke=\"black\" points=\"308.5,-190.1 305,-180.1 301.5,-190.1 308.5,-190.1\"/>\n",
       "</g>\n",
       "<!-- LungParench -->\n",
       "<g id=\"node7\" class=\"node\">\n",
       "<title>LungParench</title>\n",
       "<ellipse fill=\"none\" stroke=\"black\" cx=\"445\" cy=\"-162\" rx=\"58\" ry=\"18\"/>\n",
       "<text text-anchor=\"middle\" x=\"445\" y=\"-158.3\" font-family=\"Times,serif\" font-size=\"14.00\">LungParench</text>\n",
       "</g>\n",
       "<!-- Disease&#45;&gt;LungParench -->\n",
       "<g id=\"edge6\" class=\"edge\">\n",
       "<title>Disease&#45;&gt;LungParench</title>\n",
       "<path fill=\"none\" stroke=\"black\" d=\"M330.35,-220.32C351.59,-209.7 382.25,-194.38 406.51,-182.24\"/>\n",
       "<polygon fill=\"black\" stroke=\"black\" points=\"408.08,-185.37 415.47,-177.77 404.96,-179.1 408.08,-185.37\"/>\n",
       "</g>\n",
       "<!-- LungFlow -->\n",
       "<g id=\"node8\" class=\"node\">\n",
       "<title>LungFlow</title>\n",
       "<ellipse fill=\"none\" stroke=\"black\" cx=\"568\" cy=\"-162\" rx=\"47.5\" ry=\"18\"/>\n",
       "<text text-anchor=\"middle\" x=\"568\" y=\"-158.3\" font-family=\"Times,serif\" font-size=\"14.00\">LungFlow</text>\n",
       "</g>\n",
       "<!-- Disease&#45;&gt;LungFlow -->\n",
       "<g id=\"edge7\" class=\"edge\">\n",
       "<title>Disease&#45;&gt;LungFlow</title>\n",
       "<path fill=\"none\" stroke=\"black\" d=\"M338.46,-224.91C379.49,-214.89 451.09,-197.03 512,-180 515.53,-179.01 519.19,-177.96 522.85,-176.89\"/>\n",
       "<polygon fill=\"black\" stroke=\"black\" points=\"523.92,-180.22 532.52,-174.03 521.94,-173.51 523.92,-180.22\"/>\n",
       "</g>\n",
       "<!-- Sick -->\n",
       "<g id=\"node9\" class=\"node\">\n",
       "<title>Sick</title>\n",
       "<ellipse fill=\"none\" stroke=\"black\" cx=\"86\" cy=\"-162\" rx=\"27\" ry=\"18\"/>\n",
       "<text text-anchor=\"middle\" x=\"86\" y=\"-158.3\" font-family=\"Times,serif\" font-size=\"14.00\">Sick</text>\n",
       "</g>\n",
       "<!-- Disease&#45;&gt;Sick -->\n",
       "<g id=\"edge8\" class=\"edge\">\n",
       "<title>Disease&#45;&gt;Sick</title>\n",
       "<path fill=\"none\" stroke=\"black\" d=\"M271.42,-224.99C234.31,-215.74 173.05,-199.3 122,-180 120.16,-179.3 118.28,-178.55 116.4,-177.76\"/>\n",
       "<polygon fill=\"black\" stroke=\"black\" points=\"117.64,-174.48 107.08,-173.64 114.81,-180.88 117.64,-174.48\"/>\n",
       "</g>\n",
       "<!-- LVHreport -->\n",
       "<g id=\"node10\" class=\"node\">\n",
       "<title>LVHreport</title>\n",
       "<ellipse fill=\"none\" stroke=\"black\" cx=\"675\" cy=\"-90\" rx=\"50.09\" ry=\"18\"/>\n",
       "<text text-anchor=\"middle\" x=\"675\" y=\"-86.3\" font-family=\"Times,serif\" font-size=\"14.00\">LVHreport</text>\n",
       "</g>\n",
       "<!-- LVH&#45;&gt;LVHreport -->\n",
       "<g id=\"edge9\" class=\"edge\">\n",
       "<title>LVH&#45;&gt;LVHreport</title>\n",
       "<path fill=\"none\" stroke=\"black\" d=\"M665.9,-144.05C667.23,-136.35 668.82,-127.03 670.31,-118.36\"/>\n",
       "<polygon fill=\"black\" stroke=\"black\" points=\"673.8,-118.73 672.04,-108.28 666.9,-117.54 673.8,-118.73\"/>\n",
       "</g>\n",
       "<!-- HypDistrib -->\n",
       "<g id=\"node11\" class=\"node\">\n",
       "<title>HypDistrib</title>\n",
       "<ellipse fill=\"none\" stroke=\"black\" cx=\"224\" cy=\"-90\" rx=\"50.09\" ry=\"18\"/>\n",
       "<text text-anchor=\"middle\" x=\"224\" y=\"-86.3\" font-family=\"Times,serif\" font-size=\"14.00\">HypDistrib</text>\n",
       "</g>\n",
       "<!-- DuctFlow&#45;&gt;HypDistrib -->\n",
       "<g id=\"edge10\" class=\"edge\">\n",
       "<title>DuctFlow&#45;&gt;HypDistrib</title>\n",
       "<path fill=\"none\" stroke=\"black\" d=\"M188.14,-144.41C193.73,-136.08 200.64,-125.8 206.89,-116.49\"/>\n",
       "<polygon fill=\"black\" stroke=\"black\" points=\"209.95,-118.21 212.62,-107.96 204.14,-114.31 209.95,-118.21\"/>\n",
       "</g>\n",
       "<!-- CardiacMixing&#45;&gt;HypDistrib -->\n",
       "<g id=\"edge11\" class=\"edge\">\n",
       "<title>CardiacMixing&#45;&gt;HypDistrib</title>\n",
       "<path fill=\"none\" stroke=\"black\" d=\"M286.21,-144.76C275.51,-135.51 261.92,-123.77 250.18,-113.63\"/>\n",
       "<polygon fill=\"black\" stroke=\"black\" points=\"252.26,-110.8 242.41,-106.91 247.68,-116.1 252.26,-110.8\"/>\n",
       "</g>\n",
       "<!-- HypoxiaInO2 -->\n",
       "<g id=\"node12\" class=\"node\">\n",
       "<title>HypoxiaInO2</title>\n",
       "<ellipse fill=\"none\" stroke=\"black\" cx=\"351\" cy=\"-90\" rx=\"59.29\" ry=\"18\"/>\n",
       "<text text-anchor=\"middle\" x=\"351\" y=\"-86.3\" font-family=\"Times,serif\" font-size=\"14.00\">HypoxiaInO2</text>\n",
       "</g>\n",
       "<!-- CardiacMixing&#45;&gt;HypoxiaInO2 -->\n",
       "<g id=\"edge12\" class=\"edge\">\n",
       "<title>CardiacMixing&#45;&gt;HypoxiaInO2</title>\n",
       "<path fill=\"none\" stroke=\"black\" d=\"M316.14,-144.05C321.62,-135.71 328.33,-125.49 334.41,-116.25\"/>\n",
       "<polygon fill=\"black\" stroke=\"black\" points=\"337.4,-118.07 339.97,-107.79 331.55,-114.22 337.4,-118.07\"/>\n",
       "</g>\n",
       "<!-- LungParench&#45;&gt;HypoxiaInO2 -->\n",
       "<g id=\"edge13\" class=\"edge\">\n",
       "<title>LungParench&#45;&gt;HypoxiaInO2</title>\n",
       "<path fill=\"none\" stroke=\"black\" d=\"M423.67,-145.12C410.93,-135.63 394.56,-123.44 380.58,-113.03\"/>\n",
       "<polygon fill=\"black\" stroke=\"black\" points=\"382.36,-109.99 372.25,-106.82 378.18,-115.6 382.36,-109.99\"/>\n",
       "</g>\n",
       "<!-- CO2 -->\n",
       "<g id=\"node13\" class=\"node\">\n",
       "<title>CO2</title>\n",
       "<ellipse fill=\"none\" stroke=\"black\" cx=\"458\" cy=\"-90\" rx=\"27.5\" ry=\"18\"/>\n",
       "<text text-anchor=\"middle\" x=\"458\" y=\"-86.3\" font-family=\"Times,serif\" font-size=\"14.00\">CO2</text>\n",
       "</g>\n",
       "<!-- LungParench&#45;&gt;CO2 -->\n",
       "<g id=\"edge14\" class=\"edge\">\n",
       "<title>LungParench&#45;&gt;CO2</title>\n",
       "<path fill=\"none\" stroke=\"black\" d=\"M448.21,-143.7C449.65,-135.98 451.37,-126.71 452.96,-118.11\"/>\n",
       "<polygon fill=\"black\" stroke=\"black\" points=\"456.43,-118.57 454.82,-108.1 449.55,-117.29 456.43,-118.57\"/>\n",
       "</g>\n",
       "<!-- ChestXray -->\n",
       "<g id=\"node14\" class=\"node\">\n",
       "<title>ChestXray</title>\n",
       "<ellipse fill=\"none\" stroke=\"black\" cx=\"559\" cy=\"-90\" rx=\"48.19\" ry=\"18\"/>\n",
       "<text text-anchor=\"middle\" x=\"559\" y=\"-86.3\" font-family=\"Times,serif\" font-size=\"14.00\">ChestXray</text>\n",
       "</g>\n",
       "<!-- LungParench&#45;&gt;ChestXray -->\n",
       "<g id=\"edge15\" class=\"edge\">\n",
       "<title>LungParench&#45;&gt;ChestXray</title>\n",
       "<path fill=\"none\" stroke=\"black\" d=\"M470.02,-145.64C486.43,-135.56 508.06,-122.28 525.89,-111.33\"/>\n",
       "<polygon fill=\"black\" stroke=\"black\" points=\"528.13,-114.06 534.82,-105.85 524.47,-108.1 528.13,-114.06\"/>\n",
       "</g>\n",
       "<!-- Grunting -->\n",
       "<g id=\"node15\" class=\"node\">\n",
       "<title>Grunting</title>\n",
       "<ellipse fill=\"none\" stroke=\"black\" cx=\"114\" cy=\"-90\" rx=\"42.49\" ry=\"18\"/>\n",
       "<text text-anchor=\"middle\" x=\"114\" y=\"-86.3\" font-family=\"Times,serif\" font-size=\"14.00\">Grunting</text>\n",
       "</g>\n",
       "<!-- LungParench&#45;&gt;Grunting -->\n",
       "<g id=\"edge16\" class=\"edge\">\n",
       "<title>LungParench&#45;&gt;Grunting</title>\n",
       "<path fill=\"none\" stroke=\"black\" d=\"M402.59,-149.69C394.45,-147.67 385.98,-145.68 378,-144 284.06,-124.18 258.15,-131.25 165,-108 161.64,-107.16 158.18,-106.21 154.72,-105.19\"/>\n",
       "<polygon fill=\"black\" stroke=\"black\" points=\"155.65,-101.81 145.06,-102.2 153.58,-108.5 155.65,-101.81\"/>\n",
       "</g>\n",
       "<!-- LungFlow&#45;&gt;ChestXray -->\n",
       "<g id=\"edge17\" class=\"edge\">\n",
       "<title>LungFlow&#45;&gt;ChestXray</title>\n",
       "<path fill=\"none\" stroke=\"black\" d=\"M565.78,-143.7C564.78,-135.98 563.59,-126.71 562.49,-118.11\"/>\n",
       "<polygon fill=\"black\" stroke=\"black\" points=\"565.95,-117.57 561.2,-108.1 559.01,-118.47 565.95,-117.57\"/>\n",
       "</g>\n",
       "<!-- Sick&#45;&gt;Age -->\n",
       "<g id=\"edge18\" class=\"edge\">\n",
       "<title>Sick&#45;&gt;Age</title>\n",
       "<path fill=\"none\" stroke=\"black\" d=\"M73.2,-145.81C65.39,-136.55 55.25,-124.52 46.47,-114.09\"/>\n",
       "<polygon fill=\"black\" stroke=\"black\" points=\"48.9,-111.55 39.78,-106.16 43.55,-116.06 48.9,-111.55\"/>\n",
       "</g>\n",
       "<!-- Sick&#45;&gt;Grunting -->\n",
       "<g id=\"edge19\" class=\"edge\">\n",
       "<title>Sick&#45;&gt;Grunting</title>\n",
       "<path fill=\"none\" stroke=\"black\" d=\"M92.64,-144.41C95.87,-136.34 99.83,-126.43 103.46,-117.35\"/>\n",
       "<polygon fill=\"black\" stroke=\"black\" points=\"106.75,-118.54 107.22,-107.96 100.25,-115.94 106.75,-118.54\"/>\n",
       "</g>\n",
       "<!-- LowerBodyO2 -->\n",
       "<g id=\"node16\" class=\"node\">\n",
       "<title>LowerBodyO2</title>\n",
       "<ellipse fill=\"none\" stroke=\"black\" cx=\"228\" cy=\"-18\" rx=\"63.89\" ry=\"18\"/>\n",
       "<text text-anchor=\"middle\" x=\"228\" y=\"-14.3\" font-family=\"Times,serif\" font-size=\"14.00\">LowerBodyO2</text>\n",
       "</g>\n",
       "<!-- HypDistrib&#45;&gt;LowerBodyO2 -->\n",
       "<g id=\"edge20\" class=\"edge\">\n",
       "<title>HypDistrib&#45;&gt;LowerBodyO2</title>\n",
       "<path fill=\"none\" stroke=\"black\" d=\"M224.99,-71.7C225.43,-63.98 225.96,-54.71 226.45,-46.11\"/>\n",
       "<polygon fill=\"black\" stroke=\"black\" points=\"229.95,-46.29 227.02,-36.1 222.96,-45.89 229.95,-46.29\"/>\n",
       "</g>\n",
       "<!-- HypoxiaInO2&#45;&gt;LowerBodyO2 -->\n",
       "<g id=\"edge21\" class=\"edge\">\n",
       "<title>HypoxiaInO2&#45;&gt;LowerBodyO2</title>\n",
       "<path fill=\"none\" stroke=\"black\" d=\"M324.31,-73.81C306.62,-63.74 283.21,-50.42 263.89,-39.43\"/>\n",
       "<polygon fill=\"black\" stroke=\"black\" points=\"265.48,-36.31 255.06,-34.4 262.02,-42.39 265.48,-36.31\"/>\n",
       "</g>\n",
       "<!-- RUQO2 -->\n",
       "<g id=\"node17\" class=\"node\">\n",
       "<title>RUQO2</title>\n",
       "<ellipse fill=\"none\" stroke=\"black\" cx=\"350\" cy=\"-18\" rx=\"40.5\" ry=\"18\"/>\n",
       "<text text-anchor=\"middle\" x=\"350\" y=\"-14.3\" font-family=\"Times,serif\" font-size=\"14.00\">RUQO2</text>\n",
       "</g>\n",
       "<!-- HypoxiaInO2&#45;&gt;RUQO2 -->\n",
       "<g id=\"edge22\" class=\"edge\">\n",
       "<title>HypoxiaInO2&#45;&gt;RUQO2</title>\n",
       "<path fill=\"none\" stroke=\"black\" d=\"M350.75,-71.7C350.64,-63.98 350.51,-54.71 350.39,-46.11\"/>\n",
       "<polygon fill=\"black\" stroke=\"black\" points=\"353.89,-46.05 350.24,-36.1 346.89,-46.16 353.89,-46.05\"/>\n",
       "</g>\n",
       "<!-- CO2Report -->\n",
       "<g id=\"node18\" class=\"node\">\n",
       "<title>CO2Report</title>\n",
       "<ellipse fill=\"none\" stroke=\"black\" cx=\"460\" cy=\"-18\" rx=\"51.5\" ry=\"18\"/>\n",
       "<text text-anchor=\"middle\" x=\"460\" y=\"-14.3\" font-family=\"Times,serif\" font-size=\"14.00\">CO2Report</text>\n",
       "</g>\n",
       "<!-- CO2&#45;&gt;CO2Report -->\n",
       "<g id=\"edge23\" class=\"edge\">\n",
       "<title>CO2&#45;&gt;CO2Report</title>\n",
       "<path fill=\"none\" stroke=\"black\" d=\"M458.49,-71.7C458.71,-63.98 458.98,-54.71 459.23,-46.11\"/>\n",
       "<polygon fill=\"black\" stroke=\"black\" points=\"462.73,-46.2 459.51,-36.1 455.73,-46 462.73,-46.2\"/>\n",
       "</g>\n",
       "<!-- XrayReport -->\n",
       "<g id=\"node19\" class=\"node\">\n",
       "<title>XrayReport</title>\n",
       "<ellipse fill=\"none\" stroke=\"black\" cx=\"581\" cy=\"-18\" rx=\"52\" ry=\"18\"/>\n",
       "<text text-anchor=\"middle\" x=\"581\" y=\"-14.3\" font-family=\"Times,serif\" font-size=\"14.00\">XrayReport</text>\n",
       "</g>\n",
       "<!-- ChestXray&#45;&gt;XrayReport -->\n",
       "<g id=\"edge24\" class=\"edge\">\n",
       "<title>ChestXray&#45;&gt;XrayReport</title>\n",
       "<path fill=\"none\" stroke=\"black\" d=\"M564.33,-72.06C566.78,-64.26 569.74,-54.82 572.49,-46.08\"/>\n",
       "<polygon fill=\"black\" stroke=\"black\" points=\"575.91,-46.86 575.57,-36.27 569.23,-44.77 575.91,-46.86\"/>\n",
       "</g>\n",
       "<!-- GruntingReport -->\n",
       "<g id=\"node20\" class=\"node\">\n",
       "<title>GruntingReport</title>\n",
       "<ellipse fill=\"none\" stroke=\"black\" cx=\"80\" cy=\"-18\" rx=\"66.5\" ry=\"18\"/>\n",
       "<text text-anchor=\"middle\" x=\"80\" y=\"-14.3\" font-family=\"Times,serif\" font-size=\"14.00\">GruntingReport</text>\n",
       "</g>\n",
       "<!-- Grunting&#45;&gt;GruntingReport -->\n",
       "<g id=\"edge25\" class=\"edge\">\n",
       "<title>Grunting&#45;&gt;GruntingReport</title>\n",
       "<path fill=\"none\" stroke=\"black\" d=\"M105.77,-72.06C101.9,-64.09 97.2,-54.41 92.88,-45.51\"/>\n",
       "<polygon fill=\"black\" stroke=\"black\" points=\"95.91,-43.74 88.39,-36.27 89.61,-46.8 95.91,-43.74\"/>\n",
       "</g>\n",
       "</g>\n",
       "</svg>\n"
      ],
      "text/plain": [
       "<AGraph b'unknown' <Swig Object of type 'Agraph_t *' at 0x7e5aa51fb870>>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "child = get_example_model(\"child\")\n",
    "child_samples = child.simulate(n_samples=10000, seed=42)\n",
    "\n",
    "diag = child.to_graphviz()\n",
    "diag.layout(prog=\"dot\")\n",
    "display(diag)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9c51da29",
   "metadata": {},
   "source": [
    "Based on similar reasoning as in the first section, we can now create a knowledge base consisting of forbidden and required edges. For example, having birth asphyxia ('Disease') directly contributes to the 6 subclassses/markers of disease ('LVH', 'LungParench' etc.). It is the root cause, so it cannot have incoming edges from any of these nodes. Similarly, the CO2 level ('CO2') affects the CO2 report ('CO2Report'), and not the other way around."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "03bcfb85",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "1697474157f046a6b2cbe6f71f7fcde1",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "  0%|          | 0/5 [00:00<?, ?it/s]"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "ename": "KeyError",
     "evalue": "frozenset({'Disease', 'CO2'})",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mKeyError\u001b[0m                                  Traceback (most recent call last)",
      "Cell \u001b[0;32mIn[9], line 11\u001b[0m\n\u001b[1;32m      6\u001b[0m forbidden_edges \u001b[38;5;241m=\u001b[39m [(u, v) \u001b[38;5;28;01mfor\u001b[39;00m u, v \u001b[38;5;129;01min\u001b[39;00m itertools\u001b[38;5;241m.\u001b[39mcombinations(child\u001b[38;5;241m.\u001b[39mnodes(), \u001b[38;5;241m2\u001b[39m) \u001b[38;5;28;01mif\u001b[39;00m v \u001b[38;5;241m==\u001b[39m \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mDisease\u001b[39m\u001b[38;5;124m'\u001b[39m]\n\u001b[1;32m      8\u001b[0m expert_knowledge \u001b[38;5;241m=\u001b[39m ExpertKnowledge(\n\u001b[1;32m      9\u001b[0m     required_edges\u001b[38;5;241m=\u001b[39mrequired_edges, forbidden_edges\u001b[38;5;241m=\u001b[39mforbidden_edges\n\u001b[1;32m     10\u001b[0m )\n\u001b[0;32m---> 11\u001b[0m est_model \u001b[38;5;241m=\u001b[39m \u001b[43mPC\u001b[49m\u001b[43m(\u001b[49m\u001b[43mchild_samples\u001b[49m\u001b[43m)\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mestimate\u001b[49m\u001b[43m(\u001b[49m\u001b[43mexpert_knowledge\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mexpert_knowledge\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mci_test\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43mpillai\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43menforce_expert_knowledge\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;28;43;01mTrue\u001b[39;49;00m\u001b[43m)\u001b[49m\n\u001b[1;32m     12\u001b[0m SHD(child, est_model)\n",
      "File \u001b[0;32m~/pgmpy/examples/pgmpy/estimators/PC.py:241\u001b[0m, in \u001b[0;36mPC.estimate\u001b[0;34m(self, variant, ci_test, return_type, significance_level, max_cond_vars, expert_knowledge, enforce_expert_knowledge, n_jobs, show_progress, **kwargs)\u001b[0m\n\u001b[1;32m    238\u001b[0m     \u001b[38;5;28;01mreturn\u001b[39;00m skel, separating_sets\n\u001b[1;32m    240\u001b[0m \u001b[38;5;66;03m# Step 2: Orient the edges based on collider structures.\u001b[39;00m\n\u001b[0;32m--> 241\u001b[0m pdag \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43morient_colliders\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m    242\u001b[0m \u001b[43m    \u001b[49m\u001b[43mskel\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mseparating_sets\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mexpert_knowledge\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mtemporal_ordering\u001b[49m\n\u001b[1;32m    243\u001b[0m \u001b[43m\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m    245\u001b[0m \u001b[38;5;66;03m# Step 3: Either return the CPDAG, integrate expert knowledge or fully orient the edges to build a DAG.\u001b[39;00m\n\u001b[1;32m    246\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m expert_knowledge\u001b[38;5;241m.\u001b[39mtemporal_order \u001b[38;5;241m!=\u001b[39m [[]]:\n",
      "File \u001b[0;32m~/pgmpy/examples/pgmpy/estimators/PC.py:548\u001b[0m, in \u001b[0;36mPC.orient_colliders\u001b[0;34m(skeleton, separating_sets, temporal_ordering)\u001b[0m\n\u001b[1;32m    546\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m skeleton\u001b[38;5;241m.\u001b[39mhas_edge(X, Y):\n\u001b[1;32m    547\u001b[0m     \u001b[38;5;28;01mfor\u001b[39;00m Z \u001b[38;5;129;01min\u001b[39;00m \u001b[38;5;28mset\u001b[39m(skeleton\u001b[38;5;241m.\u001b[39mneighbors(X)) \u001b[38;5;241m&\u001b[39m \u001b[38;5;28mset\u001b[39m(skeleton\u001b[38;5;241m.\u001b[39mneighbors(Y)):\n\u001b[0;32m--> 548\u001b[0m         \u001b[38;5;28;01mif\u001b[39;00m Z \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;129;01min\u001b[39;00m \u001b[43mseparating_sets\u001b[49m\u001b[43m[\u001b[49m\u001b[38;5;28;43mfrozenset\u001b[39;49m\u001b[43m(\u001b[49m\u001b[43m(\u001b[49m\u001b[43mX\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mY\u001b[49m\u001b[43m)\u001b[49m\u001b[43m)\u001b[49m\u001b[43m]\u001b[49m:\n\u001b[1;32m    549\u001b[0m             \u001b[38;5;28;01mif\u001b[39;00m (temporal_ordering \u001b[38;5;241m==\u001b[39m \u001b[38;5;28mdict\u001b[39m()) \u001b[38;5;129;01mor\u001b[39;00m (\n\u001b[1;32m    550\u001b[0m                 (temporal_ordering[Z] \u001b[38;5;241m>\u001b[39m\u001b[38;5;241m=\u001b[39m temporal_ordering[X])\n\u001b[1;32m    551\u001b[0m                 \u001b[38;5;129;01mand\u001b[39;00m (temporal_ordering[Z] \u001b[38;5;241m>\u001b[39m\u001b[38;5;241m=\u001b[39m temporal_ordering[Y])\n\u001b[1;32m    552\u001b[0m             ):\n\u001b[1;32m    553\u001b[0m                 pdag\u001b[38;5;241m.\u001b[39mremove_edges_from([(Z, X), (Z, Y)])\n",
      "\u001b[0;31mKeyError\u001b[0m: frozenset({'Disease', 'CO2'})"
     ]
    }
   ],
   "source": [
    "required_edges = [(\"CO2\", \"CO2Report\"),\n",
    "                  (\"ChestXray\", \"XrayReport\"),\n",
    "                  (\"LVH\", \"LVHreport\"),\n",
    "                  (\"Gruntin\", \"GruntingReport\")]\n",
    "# As disease should be an exogenous node, do not allow any incoming edges except `BirthAsphyxia'.\n",
    "forbidden_edges = [(u, v) for u, v in itertools.combinations(child.nodes(), 2) if v == 'Disease']\n",
    "\n",
    "expert_knowledge = ExpertKnowledge(\n",
    "    required_edges=required_edges, forbidden_edges=forbidden_edges\n",
    ")\n",
    "est_model = PC(child_samples).estimate(expert_knowledge=expert_knowledge, ci_test='pillai', enforce_expert_knowledge=True)\n",
    "SHD(child, est_model)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "d33b6f03",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Plot the estimated model\n",
    "\n",
    "diag = est_model.to_graphviz()\n",
    "diag.layout(prog=\"dot\")\n",
    "display(diag)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.12.0"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
